﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using UnityEngine;

namespace DashFire
{
  class ResVersionInnerLoader
  {
    public static ResAsyncInfo StartLoad()
    {
      ResAsyncInfo info = new ResAsyncInfo();
      info.CurCoroutine = CoroutineProxy.Instance.StartCoroutine(StartLoadAsync(info));
      return info;
    }
    public static ResAsyncInfo LoadResByName(string abName)
    {
      ResAsyncInfo info = new ResAsyncInfo();
      ResVersionData data = ResVersionProvider.Instance.GetDataByAssetBundleName(abName);
      info.CurCoroutine = CoroutineProxy.Instance.StartCoroutine(LoadResByNameAsync(data, info));
      return info;
    }
    public static ResAsyncInfo LoadInnerResVersion()
    {
      ResAsyncInfo info = new ResAsyncInfo();
      info.CurCoroutine = CoroutineProxy.Instance.StartCoroutine(LoadInnerResVersionAsync(info));
      return info;
    }
    private static IEnumerator LoadInnerResVersionAsync(ResAsyncInfo info)
    {
      if (ResUpdateControler.s_ClientVersionInfo.IsResInnerConfigCached) {
        info.IsDone = true;
        info.Progress = 1.0f;
        yield break;
      }

      ResVersionProvider.Instance.Clear();
      string url = ResLoadHelper.GetFilePath(ResPathType.Buildin, ResUpdateConfig.s_ResInnerFile);
      ResLoadHelper.Log("LoadInnerResVersion url:" + url);
      if (!ResLoadHelper.IsResConfigCached(ResFileType.ResInner)) {
        using (WWW tWWW = new WWW(url)) {
          yield return tWWW;
          try {
            if (tWWW.error != null) {
              ResLoadHelper.Log("LoadInnerResVersion www error url:" + url);
              tWWW.Dispose();
              ResUpdateControler.s_UpdateError = ResUpdateError.RequestInnerResVersion_WWW_Error;
              yield break;
            }
            byte[] buffer = tWWW.bytes;
            if (buffer == null || buffer.Length < 0) {
              ResLoadHelper.Log("LoadInnerResVersion tWWW.byte null");
              info.IsError = true;
              ResUpdateControler.s_UpdateError = ResUpdateError.RequestInnerResVersion_Byte_Error;
              tWWW.Dispose();
              yield break;
            }
            ResVersionProvider.Instance.CollectDataFromDBC(buffer);
          } catch (System.Exception ex) {
            ResLoadHelper.Log("LoadInnerResVersion ab failed url:" + url + "ex:" + ex);
            info.IsError = true;
            ResUpdateControler.s_UpdateError = ResUpdateError.RequestInnerResVersion_Save_Error;
            yield break;
          } finally {
            tWWW.Dispose();
          }
        }
      }

      info.IsDone = true;
      info.Progress = 1.0f;
    }
    private static IEnumerator StartLoadAsync(ResAsyncInfo info)
    {
      List<string> toUpgradeRes = new List<string>();
      ResUpdateTool.SearchInnerRes(toUpgradeRes);
      if (toUpgradeRes != null && toUpgradeRes.Count > 0) {
        DateTime tStartLoad = DateTime.Now;
        long totalSize = ResLoadHelper.CaculateABSize(toUpgradeRes);
        LogicForGfxThread.UpdateLoadingTip("首次启动，正在准备资源...");
        yield return 1;
        long accSize = 0;
        List<ResAsyncInfo> asyncList = new List<ResAsyncInfo>();
        List<ResAsyncInfo> asyncDoneList = new List<ResAsyncInfo>();
        int index = 0;
        while (true) {
          while (asyncList.Count < ResUpdateConfig.s_AsyncCoroutineMax && index < toUpgradeRes.Count) {
            string abName = toUpgradeRes[index++];
            ResAsyncInfo loadAssetInfo = LoadResByName(abName);
            loadAssetInfo.Target = (System.Object)(abName);
            asyncList.Add(loadAssetInfo);
          }
          asyncDoneList.Clear();
          foreach (ResAsyncInfo loadAssetInfo in asyncList) {
            if (loadAssetInfo.IsError) {
              ResLoadHelper.Log("准备资源错误 ab:" + loadAssetInfo.Tip);
              info.IsError = true;
              ResUpdateControler.s_UpdateError = ResUpdateError.LoadInnerResVersion_Load_Error;
              yield break;
            } else if (loadAssetInfo.IsDone) {
              string abName = (string)loadAssetInfo.Target;
              ResVersionData data = ResVersionProvider.Instance.GetDataByAssetBundleName(abName);
              if (data != null) {
                accSize += data.m_Size;
              }
              double elapsed = (DateTime.Now - tStartLoad).TotalSeconds;
              if (elapsed < double.Epsilon) {
                elapsed = double.Epsilon;
              }
              //double speed = accSize / elapsed;
              info.Progress = 0.2f + 0.3f * (float)(accSize / ((totalSize > 0) ? totalSize : double.Epsilon));
              LogicForGfxThread.UpdateLoadingProgress(info.Progress);

              asyncDoneList.Add(loadAssetInfo);
            }
          }
          foreach (ResAsyncInfo loadAssetInfo in asyncDoneList) {
            asyncList.Remove(loadAssetInfo);
          }
          if (ResUpdateControler.s_DownLoadNum >= 20) {
            ResVersionLoader.SaveClientResVersion();
            ResUpdateControler.s_DownLoadNum = 0;
          }
          asyncDoneList.Clear();
          if (asyncList.Count == 0 && index >= toUpgradeRes.Count) {
            break;
          }
          yield return 1;
        }
        LogicForGfxThread.UpdateLoadingProgress(info.Progress);
      }
      LogicForGfxThread.UpdateLoadingProgress(1.0f);
      info.IsDone = true;
      info.Progress = 1.0f;
    }
    private static IEnumerator LoadResByNameAsync(ResVersionData data, ResAsyncInfo info)
    {
      string url = ResLoadHelper.GetFilePath(ResPathType.Buildin, data.m_AssetBundleName);
      using (WWW tWWW = new WWW(url)) {
        yield return tWWW;
        try {
          if (tWWW.error != null) {
            ResLoadHelper.Log("LoadRes error data:" + data.m_AssetBundleName + " Url:" + url);
            info.IsError = true;
            ResUpdateControler.s_UpdateError = ResUpdateError.LoadInnerResVersion_WWW_Error;
            tWWW.Dispose();
            yield break;
          }
          if (!ResUpdateTool.SaveCacheAB(tWWW.bytes, data, true)) {
            throw new Exception(string.Format("LoadRes save ab failed. url:{0} abName:{1}", url, data.m_AssetBundleName));
          }
        } catch (System.Exception ex) {
          ResLoadHelper.Log("LoadRes ex:" + ex);
          info.IsError = true;
          ResUpdateControler.s_UpdateError = ResUpdateError.LoadInnerResVersion_Save_Error;
          yield break;
        } finally {
          tWWW.Dispose();
        }
      }
      info.IsDone = true;
      info.Progress = 1.0f;
    }
    public static void OnFinishExtractResInner()
    {
      if (ResUpdateControler.s_DownLoadNum > 0) {
        ResVersionLoader.SaveClientResVersion();
        ResUpdateControler.s_DownLoadNum = 0;
      }
    }
  }
}
